﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GGEditor.API;
using GGEditor.Core.Commands;

namespace GGEditor.Core.Plugins
{
	public class PluginManager : IPluginManager
    {
        private PluginManager() {}

        private static readonly PluginManager instance = new PluginManager();

        private readonly IList<IPlugin> plugins = new List<IPlugin>();

        private readonly IPluginNode rootNode = new PluginNodeBuilder()
        {
            Parent = null
        };

        /// <summary>
        /// Singleton reference to global plugin manager
        /// </summary>
        public static IPluginManager Instance
        {
            get { return instance; }
        }

        #region Implementation of IPluginManager

        public IEnumerable<IPlugin> Plugins
        {
            get { return plugins; }
		}

		public IPluginNode RootNode
		{
			get { return rootNode; }
		}

        public void AddPlugin(IPlugin plugin)
        {
        	foreach (IPluginExtension extension in plugin.Extensions)
        	{
				IPluginNode parentNode = GetNode(extension.Path);
				
				if (parentNode == null)
					throw new PluginLoadDependencyException();

				foreach (IPluginNode node in extension.Nodes)
					parentNode.AddChild(node);
        	}

			plugins.Add(plugin);
			PluginAdded(plugin);

			UpdateObjects();
        }

        public void RemovePlugin(IPlugin plugin)
        {
			foreach (IPluginExtension extension in plugin.Extensions)
			{
				IPluginNode parentNode = GetNode(extension.Path);

				if (parentNode == null)
					throw new PluginLoadDependencyException();

				foreach (IPluginNode node in extension.Nodes)
					parentNode.RemoveChild(node);
			}

			plugins.Remove(plugin);
			PluginRemoved(plugin);

			UpdateObjects();
        }

        public IPluginNode GetNode(string path)
        {
            if (path == PluginPaths.PathSeparator.ToString())
                return RootNode;
            return GetNode(RootNode, PluginPaths.Split(path), 0);
        }

        private IPluginNode GetNode(IPluginNode node, string[] parts, int part)
        {
            if (node == null)
                return null;
            if (part == parts.Length - 1)
                return node;
            return GetNode(node.GetChildNode(parts[part + 1]), parts, part + 1);
        }

        public void UpdateObjects()
        {
            RootNode.Update();
        }

		public event PluginManagerEventHandler PluginAdded = delegate { };

		public event PluginManagerEventHandler PluginRemoved = delegate { };

		#endregion

		#region Implementation of IPluginContext

		public object GetObject(string path)
		{
			IPluginNode node = GetNode(path);
			if (node == null)
				return null;
			return node.Object;
		}

		public T GetObject<T>(string path) where T : class
		{
			return GetObject(path) as T;
		}

		public void DoCommand(string cmdPath)
		{

			//CommandManager.Instance.DoCommand(cmdPath);
		}

		#endregion
    }
}